package com.xzzz.irda.auth.server.authentication;

import com.xzzz.irda.auth.core.authorization.Authorization;
import com.xzzz.irda.auth.core.token.AccessToken;
import com.xzzz.irda.auth.server.pojo.LoginMetadata;
import com.xzzz.irda.auth.server.pojo.LoginEventMetadata;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;

/**
 * token service, 提供方法级别的登录功能, 可用于 dubbo 接口实现方调用
 *
 * @author wangyf
 * 
 */
@Slf4j
public class TokenService implements ApplicationContextAware {

    private final AuthenticationManagerStrategy authenticationManagerStrategy;

    private final GrantTypeHandler grantTypeHandler;

    private ApplicationContext applicationContext;

    public TokenService(AuthenticationManagerStrategy authenticationManagerStrategy, GrantTypeHandler grantTypeHandler) {
        this.authenticationManagerStrategy = authenticationManagerStrategy;
        this.grantTypeHandler = grantTypeHandler;
    }

    public AccessToken login(LoginMetadata loginMetadata, LoginEventMetadata loginEventMetadata) {
        // 1. 鉴别授权类型
        Authorization authorization = grantTypeHandler.createAuthorization(loginMetadata);

        // 2. 生成授权对象
        authorization = authenticationManagerStrategy.build(authorization, loginMetadata);

        if (null == loginEventMetadata) {
            loginEventMetadata = new LoginEventMetadata()
                    .setLoginIp("NONE")
                    .setUserAgent("NONE");
        }
        loginEventMetadata.setGrantType(authorization.getGrantType())
                .setUserId(authorization.getAccessToken().getUserId());

        // 3. 发布登录事件
        this.publishEvent(new AuthLoginEvent(loginEventMetadata));
        return authorization.getAccessToken();
    }

    /**
     * 登出功能
     */
    public void logout(String token) {
        authenticationManagerStrategy.removeAuthorization(token);
    }


    /**
     * 检查 token
     *
     * @return token 信息
     */
    public AccessToken checkToken(String token) {
        return authenticationManagerStrategy.getAuthorization(token).getAccessToken();
    }


    /**
     * 检查授权信息
     *
     * @return 授权主体信息
     */
    public Authorization checkAuthorization(String token) {
        return authenticationManagerStrategy.getAuthorization(token);
    }


    /**
     * 在TOKEN不变的情况下,刷新授权信息
     *
     * @param token token
     */
    public void refreshAuthorization(String token) {
        authenticationManagerStrategy.refreshAuthorization(token);
    }

    private void publishEvent(ApplicationEvent event) {
        applicationContext.publishEvent(event);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
